﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.OleDb;
using System.Data.SqlClient;
using System.IO;
using System.Threading;
using System.Web;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using Cms.Application;
using Cms.Application.Admin.Views;
using Cms.Application.IO;
using Cms.Data;
using Cms.Data.ORM;
using Cms.Domain;
using Cms.Domain.RepositoryInterfaces;
using Cms.Utilities;
using Cms.Web.Framework.Controls;
using iLib.Web.UI;
using MySql.Data.MySqlClient;

namespace Cms.Web.UI
{
    public partial class ConfigureDatabase : AdminBasePage, IConfigureDatabaseView
    {
        #region IConfigureDatabaseView Members

        public string DatabaseType
        {
            get { return ddlDatabaseTypes.SelectedValue; }
            set { ddlDatabaseTypes.SelectedValue = value; }
        }

        public string ServerName
        {
            get { return txtServer.Text; }
        }

        public string DatabaseName
        {
            get { return txtDatabase.Text; }
        }

        public string Username
        {
            get { return txtUsername.Text; }
        }

        public string Password
        {
            get { return txtPassword.Text; }
        }

        public string ContextTranslationFile
        {
            get { return "Admin/Translations/ConfigureDatabase.xml"; }
        }

        #endregion

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            pnlError.Visible = false;
            if (Page.IsPostBack)
            {
                return;
            }
            if (!HttpContext.Current.IsDebuggingEnabled)
            {
                File.Delete(Url.PhysicalPath + "Install.aspx");
            }
            litApplicationPath.Text = Url.PhysicalPath;
            txtPath.Text = Url.PhysicalPath + "Fredium.mdb";
            if (Request.QueryString["action"] == "CreateDatabase")
            {
                CreateDatabase();
            }
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            pnlFile.Visible = ddlDatabaseTypes.SelectedValue == "Access";
            pnlServer.Visible = !pnlFile.Visible;
            trSqlServerConnectionType.Visible = ddlDatabaseTypes.SelectedValue.IndexOf("SqlServer") == 0;
            trUsername.Visible = !trSqlServerConnectionType.Visible ||
                                 (trSqlServerConnectionType.Visible &&
                                  ddlSqlServerConnectionTypes.SelectedValue != "Trusted");
            trPassword.Visible = trUsername.Visible;
        }

        protected void lbConfigure_Click(object sender, EventArgs e)
        {
            string webConfig = HttpContext.Current.Server.MapPath(Url.VirtualPath + "web.config");
            if (!File.Exists(webConfig))
            {
                return;
            }
            string connectionString = BuildConnectionString();
            TestConnectionString(connectionString);
            if (pnlError.Visible)
            {
                return;
            }
            XDocument config = XDocument.Load(Url.PhysicalPath + "web.config");
            XElement element = config.XPathSelectElement("/configuration/appSettings/add[@key='DatabaseType']");
            element.Attribute("value").SetValue(ddlDatabaseTypes.SelectedValue);
            element = config.XPathSelectElement("/configuration/connectionStrings/add[@name='Fredium']");
            element.Attribute("connectionString").SetValue(connectionString);
            var writer = new XmlTextWriter(Url.PhysicalPath + "web.config", null) { Formatting = Formatting.Indented };
            config.WriteTo(writer);
            writer.Flush();
            writer.Close();
            Thread.Sleep(1000);
            if (ConfigurationManager.AppSettings["AspNetIsRestartedManually"] == "true")
            {
                pnlManualRestart.Visible = true;
                return;
            }
            Response.Redirect("~/ConfigureDatabase.aspx?action=CreateDatabase");
        }

        private void CreateDatabase()
        {
            Installer installer = new Installer();
            installer.CreateDatabase();
            installer.CreatePermissions();
            installer.CreateFieldTypes();
            IDiskAccess diskAccess = new DiskAccess();
            diskAccess.CreateDirectory("__System\\MasterTemplates");
            diskAccess.CreateDirectory("__System\\DetailTemplates");
            diskAccess.CreateDirectory("__System\\Stylesheets");
            diskAccess.CreateDirectory("__System\\ApplicationPages");
            diskAccess.CreateDirectory("Admin\\Resources\\Temp\\1");
            if (!HttpContext.Current.IsDebuggingEnabled)
            {
                File.Delete(Url.PhysicalPath + "ConfigureDatabase.aspx");
            }
            XDocument config = XDocument.Load(Url.PhysicalPath + "web.config");
            XElement element = config.XPathSelectElement("/configuration/system.web/httpModules");
            element.Add(new XElement(
                "add",
                new XAttribute("name", "SessionManager"),
                new XAttribute("type", "Cms.Data.ORM.SessionManager, Cms.Data")));
            element.Add(new XElement(
                "add",
                new XAttribute("name", "RequestStart"),
                new XAttribute("type", "Cms.Web.Framework.Infrastructure.RequestStart, Cms.Web.Framework")));
            element.Add(new XElement(
                "add",
                new XAttribute("name", "UrlRewriter"),
                new XAttribute("type", "Cms.Web.Framework.Infrastructure.UrlRewriter, Cms.Web.Framework")));
            element = config.XPathSelectElement("/configuration/system.webServer/modules");
            if (element != null)
            {
                element.Add(new XElement(
                    "add",
                    new XAttribute("name", "SessionManager"),
                    new XAttribute("type", "Cms.Data.ORM.SessionManager, Cms.Data")));
                element.Add(new XElement(
                    "add",
                    new XAttribute("name", "RequestStart"),
                    new XAttribute("type", "Cms.Web.Framework.Infrastructure.RequestStart, Cms.Web.Framework")));
                element.Add(new XElement(
                    "add",
                    new XAttribute("name", "UrlRewriter"),
                    new XAttribute("type", "Cms.Web.Framework.Infrastructure.UrlRewriter, Cms.Web.Framework")));
            }
            var writer = new XmlTextWriter(Url.PhysicalPath + "web.config", null) { Formatting = Formatting.Indented };
            config.WriteTo(writer);
            writer.Flush();
            writer.Close();

            // Get the newly created admin from the database
            IAdministratorRepository adminRepository = new AdministratorRepository();
            IList<Administrator> admins = adminRepository.GetAdministrators();
            if (admins.Count != 1)
            {
                Logging.LogInfo("ConfigureDatabase has not created exactly one administrator.");
                return;
            }
            Administrator admin = admins[0];
            string encryptedCredentials = Cipher.Encrypt(admin.Username + (char)9 + admin.Password);
            Response.Redirect("Admin/Default.aspx?credentials=" + Server.UrlEncode(encryptedCredentials));
        }
        
        private string BuildConnectionString()
        {
            string connectionString = string.Empty;
            switch (ddlDatabaseTypes.SelectedValue)
            {
                case "SqlServer2008":
                case "SqlServer2005":
                case "SqlServer2000":
                    switch (ddlSqlServerConnectionTypes.SelectedValue)
                    {
                        case "Standard":
                            connectionString = "Data Source=" + txtServer.Text + ";Initial Catalog=" + txtDatabase.Text +
                                               ";User Id=" + txtUsername.Text + ";Password=" + txtPassword.Text + ";";
                            break;
                        case "Trusted":
                            connectionString = "Server=" + txtServer.Text + ";Database=" + txtDatabase.Text +
                                               ";Trusted_Connection=True;";
                            break;
                        case "IpAddress":
                            connectionString = "Data Source=" + txtServer.Text +
                                               ";Network Library=DBMSSOCN;Initial Catalog=" + txtDatabase.Text +
                                               ";User Id=" + txtUsername.Text + ";Password=" + txtPassword.Text + ";";
                            break;
                    }
                    break;
                case "MySql":
                    connectionString = "Server=" + txtServer.Text + ";Database=" + txtDatabase.Text +
                                       ";Uid=" + txtUsername.Text + ";Pwd=" + txtPassword.Text + ";";
                    break;
                case "Access":
                    connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + txtPath.Text +
                                       ";User Id=;Password=;";
                    break;
            }
            return connectionString;
        }

        private void TestConnectionString(string connectionString)
        {
            switch (ddlDatabaseTypes.SelectedValue)
            {
                case "SqlServer2008":
                case "SqlServer2005":
                case "SqlServer2000":
                    SqlConnection sqlConnection = null;
                    try
                    {
                        sqlConnection = new SqlConnection(connectionString);
                        sqlConnection.Open();
                        sqlConnection.Close();
                    }
                    catch
                    {
                        pnlError.Visible = true;
                    }
                    finally
                    {
                        if (sqlConnection != null)
                            sqlConnection.Dispose();
                    }
                    break;
                case "MySql":
                    MySqlConnection mySqlConnection = null;
                    try
                    {
                        mySqlConnection = new MySqlConnection(connectionString);
                        mySqlConnection.Open();
                        mySqlConnection.Close();
                    }
                    catch
                    {
                        pnlError.Visible = true;
                    }
                    finally
                    {
                        if (mySqlConnection != null)
                            mySqlConnection.Dispose();
                    }
                    break;
                case "Access":
                    OleDbConnection oleDbConnection = null;
                    try
                    {
                        oleDbConnection = new OleDbConnection(connectionString);
                        oleDbConnection.Open();
                        oleDbConnection.Close();
                    }
                    catch
                    {
                        pnlError.Visible = true;
                    }
                    finally
                    {
                        if (oleDbConnection != null)
                            oleDbConnection.Dispose();
                    }
                    break;
            }
        }
    }
}